###本模块主要为西语短信大类分类模块，改自别人代码。
###本模块主要为计数特征，所以不再分子模块

import datetime
import json
import os
import re
import sys
from copy import deepcopy

import pytz

from feature_set.base_feature import BaseFeature, RequstData
from feature_set.sms.un.sms_es_cate0_v1.SmsEsCate0V1ClfModel import SmsEsCate0V1ClfModel


class SmsEsCate0V1(BaseFeature):

    def __init__(self):
        super().__init__()

        ##定位配置文件目录
        self.root_dir = self.get_root_dir(os.path.abspath("."))
        self.conf_dir = os.path.join(self.root_dir, "feature_conf")

        self.day_section = [(15, "d15"), (30, "m1"), (90, "m3"), (sys.maxsize, "all")]

        self.cate_list_es = [
            "ips",
            "bank",
            "loan",
            "pay",
            "coin",
            "retail",
            "ins",
            "express",
            "takeout",
            "bet",
            "travel",
            "energy",
            "tv",
            "device",
            "tools",
            "game",
            "social",
            "gov",
            "medical",
            "edu",
            "job",
            "other",
            "fs",
        ]
        self.model = SmsEsCate0V1ClfModel()

        ##需要根据不同国家进行重写
        self.country_info = None
        self.body_name = None
        self.type_name = None
        self.phone_name = None
        self.time_name = None

    def load_conf(self):
        pass

    ###對外暴露的接口函數，返回特征
    def gen_features(self, request_data):
        rel = {}
        try:
            msg_list = self.load_request(request_data)
        except AssertionError as e:
            rel.update(self.init_cate_features())
            rel = {k: (-999 if v == -1 else v) for k, v in rel.items()}
            return rel
        rel = self.get_features(msg_list)
        rel = {k: (-999 if v == -1 else v) for k, v in rel.items()}
        print(rel)
        return rel

    ##对传来的数据进行规范化处理
    def load_request(self, request_data):
        apply_time = self.trans_str_to_time(request_data.apply_time)

        try:
            sms_list = []
            sms_data = request_data.data_sources["sms_data"]
            sms_list = json.loads(sms_data) if type(sms_data) == str else sms_data
        except:
            pass

        if len(sms_list) == 0 or type(sms_list) != list:
            assert (
                1 == 0
            ), "传入的sms_json无法解析或者解析后异常(不是list，或者为空list)"

        name_trans_hash = {
            "sender": self.phone_name,
            "content": self.body_name,
            "type": self.type_name,
            "sms_time": self.time_name,
        }

        trans_sms_list = []
        for sms in sms_list:
            if (
                self.phone_name not in sms
                or self.body_name not in sms
                or self.type_name not in sms
                or self.time_name not in sms
                or sms[self.time_name] == ""
            ):
                continue
            trans_sms = {}
            trans_sms["sender"] = sms[name_trans_hash["sender"]]
            trans_sms["sms_time"] = datetime.datetime.utcfromtimestamp(
                int(sms[name_trans_hash["sms_time"]]) // 1000
            ) + datetime.timedelta(hours=self.country_info["time_zone"])

            trans_sms["type"] = int(sms[name_trans_hash["type"]])
            trans_sms["content"] = sms[name_trans_hash["content"]]
            trans_sms["diff_days"] = (
                apply_time.date() - trans_sms["sms_time"].date()
            ).days
            trans_sms_list.append(deepcopy(trans_sms))
        sorted_msg_list = sorted(
            trans_sms_list, key=lambda x: x["sms_time"], reverse=True
        )[:3000]
        clean_sorted_sms_list = [
            trans_sms
            for trans_sms in sorted_msg_list
            if trans_sms["sms_time"] < self.trans_str_to_time(request_data.apply_time)
            and trans_sms["type"] == 1
        ]
        return clean_sorted_sms_list

    ###特征初始化函數
    def init_cate_features(self):
        cate_list_merge = list(set(self.cate_list_es))
        feature_dict = {}
        for ds in self.day_section:
            for cate in cate_list_merge:
                feature_dict[self.generate_feature_name([cate, "cnt", ds[1]])] = 0
                feature_dict[self.generate_feature_name([cate, "cnt_ratio", ds[1]])] = (
                    0.0
                )
                feature_dict[self.generate_feature_name([cate, "phonecnt", ds[1]])] = 0
                feature_dict[
                    self.generate_feature_name([cate, "phonecnt_ratio", ds[1]])
                ] = 0.0
                feature_dict[
                    self.generate_feature_name([cate, "cnt_density", ds[1]])
                ] = -1.0
            feature_dict[self.generate_feature_name(["cate_cnt", ds[1]])] = 0
            feature_dict[self.generate_feature_name(["cnt", ds[1]])] = 0
            feature_dict[self.generate_feature_name(["phonecnt", ds[1]])] = 0
            feature_dict[self.generate_feature_name(["cnt_density", ds[1]])] = -1.0
        return feature_dict

    ###特征計算函數
    def get_features(self, msg_list: list) -> dict:
        cate_list = self.msg_classify(msg_list)
        tag_list = [{} for _ in range(len(msg_list))]
        for idx in range(len(msg_list)):
            tag_list[idx]["diff_days"] = msg_list[idx]["diff_days"]
            tag_list[idx]["cate"] = cate_list[idx]
            tag_list[idx]["phone"] = msg_list[idx]["sender"]
        cate_dict = {}
        diff_days_dict = {}
        for tag in tag_list:
            for ds in self.day_section:
                if ds[1] not in cate_dict:
                    cate_dict[ds[1]] = {}
                    cate_dict[ds[1]]["all"] = []
                if ds[1] not in diff_days_dict:
                    diff_days_dict[ds[1]] = {}
                    diff_days_dict[ds[1]]["all"] = []
                if tag["diff_days"] > ds[0]:
                    continue
                cate = tag["cate"]
                if cate not in cate_dict[ds[1]]:
                    cate_dict[ds[1]][cate] = []
                if cate not in diff_days_dict[ds[1]]:
                    diff_days_dict[ds[1]][cate] = []
                cate_dict[ds[1]][cate].append(tag["phone"])
                cate_dict[ds[1]]["all"].append(tag["phone"])
                diff_days_dict[ds[1]][cate].append(tag["diff_days"])
                diff_days_dict[ds[1]]["all"].append(tag["diff_days"])

        cate_features = self.init_cate_features()
        for ds in cate_dict:
            all_phone = cate_dict[ds]["all"]
            all_msg_cnt = len(all_phone)
            all_phone_cnt = len(set(all_phone))
            cate_features[self.generate_feature_name(["cnt", ds])] = all_msg_cnt
            cate_features[self.generate_feature_name(["phonecnt", ds])] = all_phone_cnt
            cate_cnt = 0
            for cate in cate_dict[ds]:
                if cate == "all":
                    continue
                cate_cnt += 1
                msg_cnt = len(cate_dict[ds][cate])
                phone_cnt = len(set(cate_dict[ds][cate]))
                msg_cnt_ratio = (
                    0.0 if all_msg_cnt == 0 else float(msg_cnt) / all_msg_cnt
                )
                phone_cnt_ratio = (
                    0.0 if all_phone_cnt == 0 else float(phone_cnt) / all_phone_cnt
                )
                cate_features[self.generate_feature_name([cate, "cnt", ds])] = msg_cnt
                cate_features[self.generate_feature_name([cate, "phonecnt", ds])] = (
                    phone_cnt
                )
                cate_features[self.generate_feature_name([cate, "cnt_ratio", ds])] = (
                    msg_cnt_ratio
                )
                cate_features[
                    self.generate_feature_name([cate, "phonecnt_ratio", ds])
                ] = phone_cnt_ratio
            cate_features[self.generate_feature_name(["cate_cnt", ds])] = cate_cnt
        for ds in diff_days_dict:
            for cate in diff_days_dict[ds]:
                if len(diff_days_dict[ds][cate]) > 0:
                    density = self.calculate_density(diff_days_dict[ds][cate])
                    cate_features[
                        self.generate_feature_name([cate, "cnt_density", ds])
                    ] = density
        return cate_features


    ###短信分類函數
    def msg_classify(self, msg_list):
        # 构造模型输入，phone是字符串拼接到短信内容，否则不拼接
        input_text_list = []
        for msg in msg_list:
            input_text = msg["content"]
            if re.findall("[A-Za-z]", msg["sender"], re.I):
                input_text = "%s %s" % (msg["sender"], msg["content"])
            input_text_list.append(input_text)
        # 去重，提高预测速度
        input_text_list_uniq = list(set(input_text_list))
        tags = self.model.predict(input_text_list_uniq)
        predict_dict = dict(zip(input_text_list_uniq, tags))
        cate_list = self.cate_list_es
        predict_cate_list = [cate_list[predict_dict[x]] for x in input_text_list]
        return predict_cate_list

    ###幫助計算特征名字
    def generate_feature_name(self, tag_list):
        clean_tag_list = [
            tag.replace("all", "") for tag in tag_list if tag.replace("all", "") != ""
        ]
        return "_".join(clean_tag_list)

    ###計算聯繫密度
    def calculate_density(self, data_list):
        data_list.sort()
        result = pow(data_list[0], 2)
        for i in range(1, len(data_list)):
            result += pow((data_list[i] - data_list[i - 1]), 2)
        density = pow(result, 0.5)
        return density

    ###字符串转datatime
    def trans_str_to_time(self, str_time):
        return datetime.datetime.strptime(str_time, "%Y-%m-%d %H:%M:%S")

    ###定位根目录
    def get_root_dir(self,path):
        path_list=path.split(os.path.sep)
        index=path_list.index("featurelib")
        return os.path.sep.join(path_list[:index+1])
